﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;
using Kooboo.Collections;
using System.Web.Script.Serialization;
using System.ComponentModel.Composition;

namespace Kooboo.Commerce.Repositories
{
    [Export(typeof(IProductTypeRepository))]
    public partial class EntityRepositories : IProductTypeRepository
    {
       

        public IQueryable<IProductType> ProductTypes
        {
            get
            {
                return this.DataReaderContext.ProductTypes;
            }
        }

        public void Post(IProductType productType)
        {
            Contract.Requires(productType != null);

            var item = new ProductType();

            item.Name = productType.Name;
         
            item.SkuAlias = productType.SkuAlias;
            item.IsEnable = productType.IsEnable;
            item.HasDescription = productType.HasDescription;
            item.HasPackageSize = productType.HasPackageSize;
            item.HasSummary = productType.HasSummary;
            item.HasWeight = productType.HasWeight;

            this.DataWriterContext.ProductTypes.InsertOnSubmit(item);

       
            foreach (var i in productType.CustomFields)
            {
                AddCustomField(item,i);
            }


            foreach (var i in productType.Variations)
            {
                AddVariation(item,i);
            }




            this.DataWriterContext.SubmitChanges();
        }

  


        public void Put(IProductType productType)
        {
            Contract.Requires(productType != null);

            var item = this.DataWriterContext.ProductTypes
                .Where(i => i.Id == productType.Id)
                .FirstOrDefault();

            if (item == null)
            {
                throw new KeyNotFoundException("ProductType:" + productType.Id.ToString());
            }

            item.Name = productType.Name;
            item.SkuAlias = productType.SkuAlias;
            item.IsEnable = productType.IsEnable;
            item.HasDescription = productType.HasDescription;
            item.HasPackageSize = productType.HasPackageSize;
            item.HasSummary = productType.HasSummary;
            item.HasWeight = productType.HasWeight;

         
            #region Merge CustomFields

            var fields = this.DataWriterContext.ProductAttributes.Where(i => i.ProductTypeId == item.Id && i.EntityType == (int)EntityType.CustomField).ToList();
            var result_fields = fields.Compare(productType.CustomFields,
                (m, n) => m.Id == n.Id,
                this.UpdateProductAttribute);

            foreach (var i in result_fields.Added)
            {
                AddCustomField(item,i);
            }

            foreach (var i in result_fields.Deleted)
            {
                this.DataWriterContext.ProductAttributes.DeleteOnSubmit(i as ProductAttribute);
            } 
            #endregion

            #region Merge Variations

            var variations = this.DataWriterContext.ProductAttributes.Where(i => i.ProductTypeId == item.Id && i.EntityType == (int)EntityType.Variation).ToList();
            var result_variations = variations.Compare(productType.Variations,
                (m, n) => m.Id == n.Id,
                this.UpdateProductAttribute);

            foreach (var i in result_variations.Added)
            {
                AddVariation(item,i);
            }

            foreach (var i in result_variations.Deleted)
            {
                this.DataWriterContext.ProductAttributes.DeleteOnSubmit(i as ProductAttribute);
            }

            #endregion


            this.DataWriterContext.SubmitChanges();
        }

   

        public void Delete(IProductType productType)
        {
            if (productType != null)
            {
                var item = this.DataWriterContext.ProductTypes
                  .Where(i => i.Id == productType.Id)
                  .FirstOrDefault();

                if (item != null)
                {
                    //this.DataContext.CustomFields.DeleteAllOnSubmit(item.CustomFields);
                    //this.DataContext.Variations.DeleteAllOnSubmit(item.Variations);

                    this.DataWriterContext.ProductTypes.DeleteOnSubmit(item);

                    this.DataWriterContext.SubmitChanges();
                }
            }
        }

      

        JavaScriptSerializer serializer = new JavaScriptSerializer();

        private void AddVariation(ProductType productType,IVariation i)
        {
            var variation = new ProductAttribute
            {
                DataFormat = (int)i.DataFormat,
                DefaultValues = i.DefaultValues,
                EntityType = (int)EntityType.Variation,
                Name = i.Name,
                ProductType = productType,
                Selections = string.Join(Environment.NewLine, i.Selections.ToArray()),
                Sequence = i.Sequence,
                WebControlName = i.WebControl.Name
            };
            this.DataWriterContext.ProductAttributes.InsertOnSubmit(variation);

            foreach (var n in i.ValidationRules)
            {
                var rule = new ValidationRule
                {
                    ErrorMessage = n.ErrorMessage,
                    Parameters = serializer.Serialize(n.Parameters),
                    ProductAttribute = variation,
                    ValidatorName = n.Validator.Name,
                };

                this.DataWriterContext.ValidationRules.InsertOnSubmit(rule);
            }
        }

        private void AddCustomField(ProductType productType,ICustomField i)
        {
            var field = new ProductAttribute
            {
                DataFormat = (int)i.DataFormat,
                DefaultValues = i.DefaultValues,
                EntityType = (int)EntityType.CustomField,
                Name = i.Name,
                ProductType = productType,
                Selections = string.Join(Environment.NewLine, i.Selections.ToArray()),
                Sequence = i.Sequence,
                WebControlName = i.WebControl.Name
            };
            this.DataWriterContext.ProductAttributes.InsertOnSubmit(field);

            foreach (var n in i.ValidationRules)
            {
                var rule = new ValidationRule
                {
                    ErrorMessage = n.ErrorMessage,
                    Parameters = serializer.Serialize(n.Parameters),
                    ProductAttribute = field,
                    ValidatorName = n.Validator.Name,
                };

                this.DataWriterContext.ValidationRules.InsertOnSubmit(rule);
            }
        }

        private void UpdateProductAttribute(IProductAttribute dataRow, IProductAttribute entity)
        {
            dataRow.DataFormat = entity.DataFormat;
            dataRow.DefaultValues = entity.DefaultValues;

            dataRow.Name = entity.Name;
            //dataRow.ProductType = entity.ProductType;
            dataRow.Selections = entity.Selections;
            dataRow.Sequence = entity.Sequence;
            dataRow.WebControl = entity.WebControl;

            var rules = dataRow.ValidationRules.Compare(entity.ValidationRules, (r1, r2) => r1.Id == r2.Id, (r1, r2) =>
            {
                r1.ErrorMessage = r2.ErrorMessage;
                r1.Parameters = r2.Parameters;
                r1.Validator = r2.Validator;
            });


            foreach (var rule_item in rules.Added)
            {
                var rule = new ValidationRule
                {
                    ErrorMessage = rule_item.ErrorMessage,
                    Parameters = serializer.Serialize(rule_item.Parameters),
                    ProductAttribute = dataRow as ProductAttribute,
                    ValidatorName = rule_item.Validator.Name,
                };

                this.DataWriterContext.ValidationRules.InsertOnSubmit(rule);
            }

            foreach (var rule_item in rules.Deleted)
            {
                this.DataWriterContext.ValidationRules.DeleteOnSubmit(rule_item as ValidationRule);
            }
        }

    }
}
